﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.IO.Ports;
using System.Threading;
using System.Runtime.InteropServices;
namespace ModemGSM
{

    public class Modem : SerialPort
    {

        #region Private vars

        private string _IMSI;
        private string _IMEI;
        private string _Model;
        private int? _BatteryLevel;
        private decimal? _SignalLevel;
        private string _SignalOper; 
        private string _Error;
        private string _CurrentChatSet;
        private bool _Online;
        private GSMIndicator _Indicators;
        private ActiveStatusEnum _ActiveStatus;
        private List<GSMAlarm> _Alarms;
        private List<string> _validCharset;
        private bool _InternalCommand;
        private Encoding _portEncode;
        private bool _ExistLineIndentification;
        private bool _EnabledLineIndentification;
        private bool _ExistSMSTextFormat;
        private bool _ExistSMSPDUFormat;
        private ModelATCommands _ValidATCommands;
        private StoragesSMS _StoragesSMS;
        private List<SMSStorage> _SMSMessages;
        private List<StatusSMSReport> _SMSStatusReport;
        private SMSService _SMSService;
        //not setting , initialize from  constructor
        private int _delayCmd;


        #endregion

        #region Events

        public delegate void SmsReportEventHandler(object sender, SmsReportEventArgs e);
        public delegate void ChangePortAutoDetectEventHandler(object sender, AutoDetectEventArgs e);
        public delegate void RingDetectEventHandler(object sender, RingEventArgs e);
        public delegate void NoCallEventHandler(object sender, NoCallEventArgs e);
        public event ChangePortAutoDetectEventHandler ChangePortAutoDetect;
        public event RingDetectEventHandler IncomingCallDetected;
        public event NoCallEventHandler NoCallDetected;
        public event SmsReportEventHandler SMSReport;

        private static string SupressResult(string Cmd)
        {
            int pos = Cmd.IndexOf(":");
            if (pos < 0)
            {
                return Cmd;
            }
            return Cmd.Substring(pos + 1);
        }
        private static string SupressCR(string Cmd)
        {
            Cmd = Cmd.Replace("\n", "");
            Cmd = Cmd.Replace("\r", "");
            return Cmd;
        }
        private static string SupressOK(string Cmd)
        {
            Cmd = Cmd.Replace("OK", "");
            return Cmd;
        }
        private static string SupressDefaut(string Cmd)
        {
            Cmd = SupressResult(Cmd);
            Cmd = SupressCR(Cmd);
            Cmd = SupressOK(Cmd);
            return Cmd.Trim();
        }
        private static string SupressDelimtStr(string Cmd)
        {
            Cmd = Cmd.Replace((char)34, new Char());
            Cmd = Cmd.Replace("\0", "");
            return Cmd;
        }

        private string[] SplitResponse(string response)
        {
            List<string> EndLines = new List<string>();
            EndLines.Add(this.NewLine);
            if (!this.NewLine.Contains("\n"))
            {
                EndLines.Add("\n");
            }
            if (!this.NewLine.Contains("\r"))
            {
                EndLines.Add("\r");
            }
            string[] result = response.Split(EndLines.ToArray(), StringSplitOptions.RemoveEmptyEntries);
            return result;
        }

        private void Modem_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            if (!base.IsOpen) return;
            if (!_InternalCommand)
            {
                Thread.Sleep(500);
                if (!base.IsOpen) return;
                string result = base.ReadExisting();
                if (result == "" || base.BytesToRead > 0)
                {
                    Thread.Sleep(500);
                    if (!base.IsOpen) return;
                    result += base.ReadExisting();
                }
                string[] results = SplitResponse(result);
                if (results.Length > 0)
                {
                    result = results[0];
                    result = SupressDefaut(result);

                    if (results[0] == ATCOMMAND.Ring || results[0] == ATCOMMAND.CRing)
                    {
                        _ActiveStatus = ActiveStatusEnum.Ringing;
                        if (_EnabledLineIndentification && results.Length > 1)
                        {
                            result = results[1];
                            result = SupressDefaut(result);
                            result = SupressDelimtStr(result);
                            results = result.Split(',');
                            string num = results[0].Trim();
                            if (IncomingCallDetected != null)
                            {
                                IncomingCallDetected(this, new RingEventArgs(num));
                            }
                        }
                    }
                    else if (results[0] == ATCOMMAND.NoAnswer)
                    {
                        _ActiveStatus = ActiveStatusEnum.NoAnswer;
                        if (NoCallDetected != null)
                        {
                            NoCallDetected(this, new NoCallEventArgs(NoCallEventEnum.NoAnswer));
                        }
                    }
                    else if (results[0] == ATCOMMAND.NoCarrier)
                    {
                        _ActiveStatus = ActiveStatusEnum.NoCarrier;
                        if (NoCallDetected != null)
                        {
                            NoCallDetected(this, new NoCallEventArgs(NoCallEventEnum.NoCarrier));
                        }
                    }
                    else if (results[0] == ATCOMMAND.NoDialtone)
                    {
                        _ActiveStatus = ActiveStatusEnum.NoDialtone;
                        if (NoCallDetected != null)
                        {
                            NoCallDetected(this, new NoCallEventArgs(NoCallEventEnum.NoDialTone));
                        }
                    }
                    else if (results[0] == ATCOMMAND.Busy)
                    {
                        _ActiveStatus = ActiveStatusEnum.Busy;
                        if (NoCallDetected != null)
                        {
                            NoCallDetected(this, new NoCallEventArgs(NoCallEventEnum.Busy));
                        }
                    }
                    else if (results[0].StartsWith(ATCOMMAND.SMSStatusReportNew))
                    { 
                        if (SMSReport != null)
                        {
                            result = results[0].Replace(ATCOMMAND.SMSStatusReportNew, "");
                            result = SupressDelimtStr(result);
                            string[] param = result.Split(',');
                            StatusSMSReport sr = new StatusSMSReport();
                            sr.DateTimeReceiver = System.DateTime.Now;
                            sr.DateTimeSend = null;
                            sr.IndexStorage = int.Parse(param[1].Trim());
                            sr.MessageSend = "";
                            sr.Number = "";
                            sr.Status = 0;
                            sr.Storage = param[0].Trim();
                            sr.TimezoneReceiver = System.TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now);
                            sr.TimezoneSend = null;
                            sr.TypeCode = ATCOMMAND.SMSStatusReportNew;
                            sr.TypeReport = TypeStatusReportEnum.ReceiverAlert;
                            SMSReport(this, new SmsReportEventArgs(sr));
                        }
                    }
                    else if (results[0].StartsWith(ATCOMMAND.SMSStatusReportConfirm))
                    { 
                        if (SMSReport != null)
                        {
                            if (SMSReport != null)
                            {
                                result = results[0].Replace(ATCOMMAND.SMSStatusReportConfirm, "");
                                result = SupressDelimtStr(result);
                                string[] param = result.Split(',');
                                StatusSMSReport sr = new StatusSMSReport();
                                string DetDt = param[4].Trim();
                                string dtaux = DetDt.Trim().Split(' ')[0];
                                string hraux = DetDt.Trim().Split(' ')[1];
                                string[] dtpart = dtaux.Split('/');
                                string[] tzpart = hraux.Split(new char[] { '-', '+' });
                                string[] hrpart = tzpart[0].Split(':');
                                sr.DateTimeSend = new DateTime(int.Parse(dtpart[0].Trim()),int.Parse(dtpart[1].Trim()),int.Parse(dtpart[2].Trim()),int.Parse(hrpart[0].Trim()),int.Parse(hrpart[1].Trim()),int.Parse(hrpart[2].Trim()));
                                sr.TimezoneSend = new TimeSpan(0, int.Parse(tzpart[1].Trim())*15, 0);
                                if (hraux.Contains("-"))
                                {
                                    sr.TimezoneSend = sr.TimezoneSend.Value.Negate();
                                }

                                DetDt = param[5].Trim();
                                dtaux = DetDt.Trim().Split(' ')[0];
                                hraux = DetDt.Trim().Split(' ')[1];
                                dtpart = dtaux.Split('/');
                                tzpart = hraux.Split(new char[] { '-', '+' });
                                hrpart = tzpart[0].Split(':');
                                sr.DateTimeReceiver = new DateTime(int.Parse(dtpart[0].Trim()), int.Parse(dtpart[1].Trim()), int.Parse(dtpart[2].Trim()), int.Parse(hrpart[0].Trim()), int.Parse(hrpart[1].Trim()), int.Parse(hrpart[2].Trim()));
                                sr.TimezoneReceiver = new TimeSpan(0, int.Parse(tzpart[1].Trim())*15, 0);
                                if (hraux.Contains("-"))
                                {
                                    sr.TimezoneReceiver = sr.TimezoneReceiver.Value.Negate();
                                }
                                sr.IndexStorage = -1;
                                sr.MessageSend = "";
                                sr.Number = param[2].Trim().Replace("+", "");
                                sr.Status = int.Parse(param[6].Trim());
                                sr.Storage = "";
                                sr.TypeCode = ATCOMMAND.SMSStatusReportConfirm;
                                sr.TypeReport = TypeStatusReportEnum.SendConfirmation;
                                SMSReport(this, new SmsReportEventArgs(sr));
                            }
                        }
                    }
                    else if (results[0].StartsWith(ATCOMMAND.SMSStatusReportConfirmStorage))
                    {
                        if (SMSReport != null)
                        {
                            result = results[0].Replace(ATCOMMAND.SMSStatusReportConfirmStorage, "");
                            result = SupressDelimtStr(result);
                            string[] param = result.Split(',');
                            StatusSMSReport sr = new StatusSMSReport();
                            sr.DateTimeReceiver = System.DateTime.Now;
                            sr.DateTimeSend = null;
                            sr.IndexStorage = int.Parse(param[1].Trim());
                            sr.MessageSend = "";
                            sr.Number = "";
                            sr.Status = 0;
                            sr.Storage = param[0].Trim();
                            sr.TimezoneReceiver = System.TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now);
                            sr.TimezoneSend = null;
                            sr.TypeCode = ATCOMMAND.SMSStatusReportConfirmStorage;
                            sr.TypeReport = TypeStatusReportEnum.ReceiverAlert;
                            SMSReport(this, new SmsReportEventArgs(sr));
                        }
                    }
                    else if (results[0].StartsWith(ATCOMMAND.SMSStatusReportConfirmForward))
                    {
                        if (SMSReport != null)
                        {
                            if (SMSReport != null)
                            {
                                result = results[0].Replace(ATCOMMAND.SMSStatusReportConfirmForward, "");
                                result = SupressDelimtStr(result);
                                string[] param = result.Split(',');
                                StatusSMSReport sr = new StatusSMSReport();
                                string DetDt = param[2].Trim();
                                string dtaux = DetDt.Trim().Split(' ')[0];
                                string hraux = DetDt.Trim().Split(' ')[1];
                                string[] dtpart = dtaux.Split('/');
                                string[] tzpart = hraux.Split(new char[] { '-', '+' });
                                string[] hrpart = tzpart[0].Split(':');
                                sr.DateTimeReceiver = new DateTime(int.Parse(dtpart[0].Trim()), int.Parse(dtpart[1].Trim()), int.Parse(dtpart[2].Trim()), int.Parse(hrpart[0].Trim()), int.Parse(hrpart[1].Trim()), int.Parse(hrpart[2].Trim()));
                                sr.TimezoneReceiver = new TimeSpan(0, int.Parse(tzpart[1].Trim())*15, 0);
                                if (hraux.Contains("-"))
                                {
                                    sr.TimezoneReceiver = sr.TimezoneReceiver.Value.Negate();
                                }
                                sr.IndexStorage = -1;
                                sr.MessageSend = "";
                                sr.Number = param[0].Trim().Replace("+","");
                                sr.Status = 0;
                                sr.Storage = "";
                                sr.TypeCode = ATCOMMAND.SMSStatusReportConfirmForward;
                                sr.TypeReport = TypeStatusReportEnum.SendConfirmation;
                                SMSReport(this, new SmsReportEventArgs(sr));
                            }
                        }
                    }
                }
            }
        }

        #endregion

        #region thread Open Port

        private static void OpenPort(object serport)
        {
            try
            {
                ((SerialPort)serport).Open();
                Thread.Sleep(100);
            }
            catch (Exception ex)
            {
                ((Modem)serport).SetError(ex.Message);
            }
        }

        #endregion

        #region constructor

        public Modem()
        {
            _delayCmd = 1;
            InitInternalVar();
        }
        public Modem(int DefaultDelayCommand)
        {
            _delayCmd = DefaultDelayCommand;
            InitInternalVar();
        }

        public Modem(int DefaultDelayCommand,string Port, int BaudRate, int Databits, StopBits Stoptb, Handshake Handshake)
        {
            base.PortName = Port;
            base.BaudRate = BaudRate;
            base.DataBits = Databits;
            base.StopBits = StopBits;
            base.Handshake = Handshake;
            _delayCmd = DefaultDelayCommand;
            InitInternalVar();
        }
        public Modem(int DefaultDelayCommand, int Port, int BaudRate, int Databits, StopBits Stoptb, Handshake Handshake)
        {
            this.PortNumber = Port;
            base.BaudRate = BaudRate;
            base.DataBits = Databits;
            base.StopBits = StopBits;
            base.Handshake = Handshake;
            _delayCmd = DefaultDelayCommand;
            InitInternalVar();
        }
        public Modem(int DefaultDelayCommand, int BaudRate, int Databits, StopBits Stoptb, Handshake Handshake)
        {
            base.BaudRate = BaudRate;
            base.DataBits = Databits;
            base.StopBits = StopBits;
            base.Handshake = Handshake;
            _delayCmd = DefaultDelayCommand;
            InitInternalVar();
        }

        #endregion

        #region Properties

        public string Error
        {
            get
            {
                return _Error;

            }
        }

        public void SetError(string err)
        {
            _Error = err;
        }

        public int OpenTimeOut { get; set; }

        public int PortNumber
        {
            get { return int.Parse(base.PortName.Replace("COM", "")); }
            set { base.PortName = "COM" + value.ToString(); }
        }

        public string Model { get { return _Model; } }

        public int? BatteryLevel { get { return _BatteryLevel; } }

        public decimal? SignalLevel { get { return _SignalLevel; } }

        public string OperName { get { return _SignalOper; } }

        public string CurrentChatSet { get { return _CurrentChatSet; } }

        public bool Online { get { return _Online; } }

        public GSMIndicator Indicators { get { return _Indicators; } }

        public ActiveStatusEnum ActiveStatus { get { return _ActiveStatus; } }

        public List<GSMAlarm> Alarms { get { return _Alarms; } }
        
        public List<string> ValidCharset { get { return _validCharset; } }

        public bool ExistLineIndentification { get { return _ExistLineIndentification; } }

        public bool EnabledLineIndentification { get { return _EnabledLineIndentification; } }

        public StoragesSMS SMSStorages { get { return _StoragesSMS; } }

        public bool ExistSMSPDU 
        { 
            set { _ExistSMSPDUFormat = value; } 
            get { return _ExistSMSPDUFormat; } 
        }

        public bool ExistSMSText 
        {
            set { _ExistSMSTextFormat = value; }
            get { return _ExistSMSTextFormat; } 
        }

        public ModelATCommands ModelATCommands { get { return _ValidATCommands; } }

        public string IMSI { get { return _IMSI; } }

        public string IMEI { get { return _IMEI; } }

        public List<SMSStorage> SMSMessages { get { return _SMSMessages; } }

        public List<SMSStorage> SMSMessagesUnread { get { return InternalMessagesLocation(LocationSMS.UnRead); } }

        public List<SMSStorage> SMSMessagesRead { get { return InternalMessagesLocation(LocationSMS.Read); } }

        public List<SMSStorage> SMSMessagesUnSent { get { return InternalMessagesLocation(LocationSMS.Unsent); } }

        public List<SMSStorage> SMSMessagesSent { get { return InternalMessagesLocation(LocationSMS.Sent); } }

        public SMSService SMSService { get { return _SMSService; } }

        public List<StatusSMSReport> SMSStatusReport { get { return _SMSStatusReport; } }

        #endregion

        #region Methods Modem

        public void ReOpen()
        {
            if (this.IsOpen)
            {
                base.Close();
                Thread.Sleep(100);
            }
            this.Open();
        }

        public new void Close()
        {
            if (this.IsOpen)
            {
                base.Close();
                this.DataReceived -= Modem_DataReceived;
                InitInternalVar();
                Thread.Sleep(100);
            }
        }

        public new void Open()
        {
            if (this.IsOpen)
            {
                this.Close();
            }
            Thread OpenThread = new Thread(OpenPort);
            _Error = "";

            OpenThread.Start(this);
            DateTime Start = DateTime.Now;
            while (!this.IsOpen)
            {
                if (!OpenThread.IsAlive)
                {
                    break;
                }
                Thread.Sleep(100);
                if (DateTime.Now.Subtract(Start).TotalMilliseconds - 100 > OpenTimeOut)
                {
                    _Error = "TIMEOUT OPEN PORT " + this.PortName;
                    break;
                }
            }
            if (OpenThread.IsAlive)
            {
                OpenThread.Abort();
            }
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                try
                {
                    this.DataReceived -= Modem_DataReceived;
                }
                catch { };
                this.DataReceived += new SerialDataReceivedEventHandler(Modem_DataReceived);
            }
            else
            {
                _Online = false;
            }
        }

        public bool KeepAlive()
        {
            _Error = "";
            if (this.IsOpen)
            {
                SendCommand("");
            }
            else
            {
                _ActiveStatus = ActiveStatusEnum.Disconnected;
                _Error = "ERROR PORT NOT OPEN";
            }
            _Online = (this.Error == "");
            if (!_Online && ActiveStatus == ActiveStatusEnum.Ready)
            {
                _ActiveStatus = ActiveStatusEnum.Offline;
            }
            return _Online;
        }

        public bool EchoOn()
        {
            _Error = "";
            if (this.IsOpen)
            {
                SendCommand(ATCOMMAND.EchoOn);
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            return (this.Error == "");
        }

        public bool EchoOff()
        {
            _Error = "";
            if (this.IsOpen)
            {
                SendCommand(ATCOMMAND.EchoOff);
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            return (this.Error == "");
        }

        public bool HangUp()
        {
            _Error = "";
            if (this.IsOpen)
            {
                SendCommand(ATCOMMAND.HangUp);
                try
                {
                    SendCommand(ATCOMMAND.HangUpCall);
                }
                catch {}
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            return (this.Error == "");
        }

        public bool Answer()
        {
            _Error = "";
            if (this.IsOpen)
            {
                SendCommand(ATCOMMAND.Answer);
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            return (this.Error == "");
        }

        public bool Call(string Number)
        {
            _Error = "";
            if (this.IsOpen)
            {
                SendNoCommand(ATCOMMAND.Dial + Number + ";");
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            return (this.Error == "");
        }

        public string SendNoCommand(string cmd)
        {
            return InternalSendCommand(cmd, true, false, false);
        }

        public string SendCommandWithContinue(string cmd)
        {
            return InternalSendCommand(cmd, true, false, true);
        }

        public string SendCommand(string cmd)
        {
            return InternalSendCommand(cmd, true, true, false);
        }

        public string SendContinueCommand(string cmd)
        {
            return InternalSendCommand(cmd, false,true,false);
        }

        private string InternalSendCommand(string cmd, bool CheckAT, bool IsCommand, bool ContinueCommand)
        {
            _Error = "";
            this.ReceivedBytesThreshold = 1;
            if (CheckAT)
            {
                if (!cmd.ToUpper().StartsWith("AT"))
                {
                    cmd = "AT" + cmd;
                }
            }
            if (!cmd.EndsWith(Char.ConvertFromUtf32(26)))
            {
                if (!cmd.EndsWith(Char.ConvertFromUtf32(13)) || !cmd.EndsWith("\n"))
                {
                    cmd += "\r";
                }
            }
            byte[] callCommand = _portEncode.GetBytes(cmd);

            StringBuilder sb = new StringBuilder();
            _InternalCommand = IsCommand;
            try
            {
                this.Write(callCommand, 0, callCommand.Length);
                Thread.Sleep(_delayCmd);
                DateTime start = DateTime.Now;
                while (true)
                {
                    if (base.BytesToRead > 0)
                    {
                        start = DateTime.Now;
                        String result = base.ReadExisting();
                        sb.Append(result);
                        if (result.Contains("OK") || result.Contains("ERROR"))
                        {
                            break;
                        }
                        if (ContinueCommand)
                        {
                            break;
                        }
                    }
                    else
                    {
                        if (DateTime.Now.Subtract(start).TotalMilliseconds > this.ReadTimeout)
                        {
                           _Error = "TIMEOUT";
                           break;
                        }
                    }
                }
            }
            catch (Exception e)
            {
                _Error = e.Message;
                sb.Length = 0;
                sb.Append("ERROR");
            }
            finally
            {
                _InternalCommand = false;
            }
            return sb.ToString();
        }

        #endregion

        #region Methods from Phone

        public void SMSAddStatusReport(StatusSMSReport item)
        {
            _SMSStatusReport.Add(item);
        }

        public void SMSAddRangeStatusReport(StatusSMSReport[] items)
        {
            _SMSStatusReport.AddRange(items);
        }
        
        public bool SMSRemoveStatusReport(StatusSMSReport item)
        {
            return _SMSStatusReport.Remove(item);
        }
        
        public void SMSRemoveAtStatusReport(int value)
        {
            _SMSStatusReport.RemoveAt(value);
        }
        
        public void SMSClearStatusReport()
        {
            _SMSStatusReport.Clear();
        }

        public StatusSMSReport SMSFindStatusReportByNumber(string number)
        {
            number = number.Replace("+", "");
            StatusSMSReport ret = null;
            foreach (var item in _SMSStatusReport)
            {
                if (item.Number.Length > number.Length)
                {
                    if (item.Number.Contains(number) && item.Status < 0)
                    {
                        ret = item;
                        break;
                    }
                }
                else if (item.Number.Length == number.Length)
                {
                    if (item.Status < 0)
                    {
                        ret = item;
                        break;
                    }
                }
                else if (item.Number.Length < number.Length)
                {
                    if (number.Contains(item.Number) && item.Status < 0)
                    {
                        ret = item;
                        break;
                    }
                }
            }
            return ret;
        }

        public StatusSMSReport SMSFindStatusReportByNumberDateSend(string number,DateTime DtSend)
        {
            number = number.Replace("+", "");
            StatusSMSReport ret = null;
            foreach (var item in _SMSStatusReport)
            {
                if (item.Number.Length > number.Length)
                {
                    if (item.Number.Contains(number) && item.Status < 0)
                    {
                        if (item.DateTimeSend.HasValue && item.DateTimeSend.Value == DtSend)
                        {
                            ret = item;
                        }
                        break;
                    }
                }
                else if (item.Number.Length == number.Length)
                {
                    if (item.DateTimeSend.HasValue && item.DateTimeSend.Value == DtSend)
                    {
                        ret = item;
                    }
                    break;
                }
                else if (item.Number.Length < number.Length)
                {
                    if (number.Contains(item.Number) && item.Status < 0)
                    {
                        if (item.DateTimeSend.HasValue && item.DateTimeSend.Value == DtSend)
                        {
                            ret = item;
                        }
                        break;
                    }
                }
            }
            return ret;
        }

        public void SetValidsAtCommand(ModelATCommands Cmd)
        {
            _ValidATCommands = Cmd;
        }

        public StoragesSMS SMSReadStorages()
        {
            _Error = "";
            StoragesSMS value = new StoragesSMS();
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.GetStorageSMS(this);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            _StoragesSMS = value;
            return _StoragesSMS;
        }

        public bool SMSStoragesWrite(string ReadDelete,string WriteSend,string Receiver)
        {
            _Error = "";
            _StoragesSMS = new StoragesSMS();
            bool value = false;
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    _StoragesSMS = GSMAPI.GetStorageSMS(this);
                    value = GSMAPI.SetStorageSMS(this,ReadDelete,WriteSend,Receiver);
                    _StoragesSMS = GSMAPI.GetStorageSMS(this);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            return value;
        }

        public PortFound[] AutoDetect()
        {
            _Error = "";
            if (this.IsOpen)
                this.Close();
            string[] sysports = System.IO.Ports.SerialPort.GetPortNames();
            List<string> ports = new List<string>();
            ports.AddRange(sysports);
            List<PortFound> ret = new List<PortFound>();
            string OldPort = this.PortName;
            foreach (var port in ports)
            {
                this.PortName = port;
                ChangePortAutoDetect(this, new AutoDetectEventArgs(port));
                try
                {
                    this.Open();
                    Thread.Sleep(200);
                    if (ModemIsPhone())
                    {
                        PortFound item = new PortFound();
                        item.COMPort = port;
                        item.Model = ReadPhoneModel();
                        ret.Add(item);
                    }
                }
                catch (Exception) { }
                finally
                {
                    if (this.IsOpen)
                    {
                        this.Close();
                    }
                }
            }
            if (this.IsOpen)
            {
                this.Close();
            }
            this.PortName = OldPort;
            return ret.ToArray();
        }

        public bool SMSReadExistTextFormat()
        {
            _Error = "";
            bool value = false;
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.SMSIsValidFormatText(this);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            _ExistSMSTextFormat = value;
            return _ExistSMSTextFormat;
        }

        public bool SMSReadExistPDUFormat()
        {
            _Error = "";
            bool value = false;
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.SMSIsValidFormatPDU(this);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            _ExistSMSPDUFormat = value;
            return _ExistSMSPDUFormat;
        }

        public bool AnaliseModemCommand(AnalyzerCMDEnum Cmd)
        {
            _Error = "";
            bool value = false;
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.AnaliseModemCMD(this,Cmd);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            return value;
        }

        public ModelATCommands AnaliseModem()
        {
            _Error = "";
            ModelATCommands value = new ModelATCommands();
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.AnaliseModemALLCMD(this);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            _ValidATCommands = value;
            return _ValidATCommands;
        }

        public bool SMSIndications(int Mode, int Delivery, int Receiver, int Report, int bufferunsolicited)
        {
            _Error = "";
            bool value = false;
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.SMSIndications(this,Mode,Delivery,Receiver,Report,bufferunsolicited);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            return value;
        }

        public bool SMSSetHeader(bool Header)
        {
            _Error = "";
            bool value = false;
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    if (Header)
                    {
                        value = GSMAPI.SMSHeaderOn(this);
                    }
                    else
                    {
                        value = GSMAPI.SMSHeaderOff(this);
                    }
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            return value;
        }

        public bool SMSDeleteMessage(int Index)
        {
            _Error = "";
            bool value = false;
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.SMSDeleteMessage(this,Index);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            return value;
        }

        public List<SMSStorage> SMSListMessagesTextFormat()
        {
            List<SMSStorage> value = SMSListMessagesTextFormat(LocationSMS.All);
            _SMSMessages = value;
            return _SMSMessages;
        }

        public List<SMSStorage> SMSListMessagesTextFormat(LocationSMS TypeLocaltion)
        {
            _Error = "";
            List<SMSStorage> value = new List<SMSStorage>();
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.SMSGetListMessageTextFormat(this, TypeLocaltion);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            return value;
        }

        public int SMSSendTextFormat(string Number, string Msg, bool SaveOutBox, string CharSet)
        {
            _Error = "";
            int value = -1;
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    if (Msg.Length > 160)
                    {
                        Msg = Msg.Substring(0, 160);
                    }
                    value = GSMAPI.SMSMessageSendText(this,Number,Msg,SaveOutBox,CharSet);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            return value;
        }
    
        public string ReadIMSI()
        {
            _Error = "";
            string value = "";
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.GetIMSI(this);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error == "")
            {
                _IMSI = value;
            }
            else
            {
                _IMSI = "";
            }
            return _IMSI;
        }

        public string ReadIMEI()
        {
            _Error = "";
            string value = "";
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.GETIMEI(this);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error == "")
            {
                _IMEI = value;
            }
            else
            {
                _IMEI = "";
            }
            return _IMEI;
        }

        public bool ReadIsLineIndentification()
        {
            _Error = "";
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    LineIdentification li = GSMAPI.GetLineIdentification(this);
                    if (li.Provisioned == null)
                    {
                        _ExistLineIndentification = false;
                        _EnabledLineIndentification = false;
                    }
                    else
                    {
                        _ExistLineIndentification = li.Provisioned.Value;
                        _EnabledLineIndentification = li.Enabled;
                    }
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error != "")
            {
                _ExistLineIndentification = false;
                _EnabledLineIndentification = false;
            }
            return _ExistLineIndentification;
        }

        public bool LineIndentificationWrite(bool ON)
        {
            _Error = "";
            bool value = false;
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.SetLineIdentification(this,ON);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            return value;
        }

        public ActiveStatusEnum ReadActiveStatus()
        {
            _Error = "";
            ActiveStatusEnum value = ActiveStatusEnum.Error;
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.GetActiveStatus(this);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error != "")
            {
                value = ActiveStatusEnum.Error;
            }
            _ActiveStatus = value;
            return _ActiveStatus;
        }

        public GSMIndicator ReadIndicators()
        {
            _Error = "";
            GSMIndicator value = new GSMIndicator();
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.GetIndicators(this);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error == "")
            {
                _Indicators = value;
            }
            else
            {
                _Indicators = null;
            }
            return _Indicators;
        }

        public decimal? ReadSignalQuality()
        {
            _Error = "";
            decimal? value = null;
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.GetSignalQuality(this);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error == "")
            {
                _SignalLevel = value;
            }
            else
            {
                _SignalLevel = null;
            } 
            return _SignalLevel;
        }

        public string ReadPhoneModel()
        {
            _Error = "";
            string value = "";
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.GetModel(this);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error == "")
            {
                _Model = value;
            }
            else
            {
                _Model = "";
            }
            return _Model;
        }

        public string ReadCurrentCharSet()
        {
            _Error = "";
            string value = "";
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.GetCurrentCharSet(this);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error == "")
            {
                _CurrentChatSet = value;
            }
            else
            {
                _CurrentChatSet = "";
            }
            return _CurrentChatSet;
        }

        public string ReadPreferredOperator()
        {
            _Error = "";
            string value = "";
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.GetPreferredOperator(this);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error == "")
            {
                _SignalOper = value;
            }
            else
            {
                _SignalOper = "";
            }
            return _SignalOper;
        }

        public List<GSMAlarm> ReadAlarms()
        {
            _Error = "";
            List<GSMAlarm> value = new List<GSMAlarm>();
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.GetAlarms(this);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            _Alarms = value;
            return _Alarms;
        }

        public List<string> ReadValidCharSets()
        {
            _Error = "";
            List<string> value = new List<string>();
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.GetListCharSet(this);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            _validCharset = value;
            return _validCharset;
        }

        public string ReadClockDate()
        {
            _Error = "";
            string value = "";
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.GetDateTime(this);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error == "")
            {
                return value.Split(',')[0];
            }
            return "";
        }

        public string ReadClockTime()
        {
            _Error = "";
            string value = "";
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.GetDateTime(this);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error == "")
            {
                return value.Split(',')[1];
            }
            return "";
        }

        public RangerValue ReadPBookRangeSim()
        {
            _Error = "";
            RangerValue value = new RangerValue();
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.GetSIMPhoneRange(this);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            return value;
        }

        public RangerValue ReadPBookRangePhone()
        {
            _Error = "";
            RangerValue value = new RangerValue();
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.GetMEMPhoneRange(this);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            return value;
        }

        public List<PhoneStorage> ReadPBookDataFrom(StorageReadEnum ReadFrom, int Start, int End,string CharSet)
        {
            _Error = "";
            List<PhoneStorage> value = new List<PhoneStorage>();
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.GetListPhones(this, CharSet, ReadFrom, Start, End);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            return value;
        }

        public int? ReadBatteryLevel()
        {
            return ReadBatteryLevel(0);
        }

        public int? ReadBatteryLevel(int Minvalue)
        {
            _Error = "";
            int? value = null;
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.GetBatteryLevel(this, Minvalue);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error != "")
            {
                value = null;
            }
            _BatteryLevel = value;
            return _BatteryLevel;
        }

        public PhoneBookMaxLength ReadPBookMaxLengthSim()
        {
            _Error = "";
            PhoneBookMaxLength value = new PhoneBookMaxLength();
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.GetPbookSIMMaxLength(this);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error != "")
            {
                value = null;
            }
            return value;
        }

        public PhoneBookMaxLength ReadPBookMaxLengthPhone()
        {
            _Error = "";
            PhoneBookMaxLength value = new PhoneBookMaxLength();
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.GetPbookMEMMaxLength(this);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error != "")
            {
                value = null;
            }
            return value;
        }

        public bool AlarmsWrite(GSMAlarm Alarm)
        {
            _Error = "";
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    GSMAPI.SetAlarm(this, Alarm);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error == "")
            {
                return true;
            } 
            return false;
        }

        public bool AlarmsDelete(int Index)
        {
            _Error = "";
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    GSMAPI.DeleteAlarm(this, Index);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error == "")
            {
                return true;
            }
            return false;
        }

        public bool CharSetWrite(string CharSet)
        {
            _Error = "";
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    GSMAPI.SetCharSet(this, CharSet);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error == "")
            {
                return true;
            }
            return false;
        }

        public bool ClockDateTimeWrite()
        {
            _Error = "";
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    ClockDateTimeWrite(System.DateTime.Now);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error == "")
            {
                return true;
            }
            return false;
        }

        public bool ClockDateTimeWrite(DateTime Date)
        {
            _Error = "";
            bool result = false;
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    string strDate = Date.ToString("yy/MM/dd");
                    strDate += "," + Date.ToString("HH:mm:ss");
                    result = GSMAPI.SetDateTime(this, strDate);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error != "")
            {
                result = false;
            }
            return result;
        }

        public int PBookSimInsert(string Name,string Number)
        {
            _Error = "";
            int value = -1;
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.AddPBookSIM(this,Name, Number);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error != "")
            {
                value = -1;
            }
            return value;
        }

        public bool PBookSimUpdate(string Index,string Name, string Number)
        {
            _Error = "";
            bool value = false;
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.UpdatePBookSIM(this,Index, Name, Number);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error != "")
            {
                value = false;
            }
            return value;
        }

        public bool PBookSimDelete(string Index)
        {
            _Error = "";
            bool value = false;
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.DeletePBookSIM(this, Index);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error != "")
            {
                value = false;
            }
            return value;
        }

        public int PBookPhoneInsert(string Name, string Number)
        {
            _Error = "";
            int value = -1;
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.AddPBookMEM(this, Name, Number);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error != "")
            {
                value = -1;
            }
            return value;
        }

        public bool PBookPhoneUpdate(string Index, string Name, string Number)
        {
            _Error = "";
            bool value = false;
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.UpadatePBookMEM(this, Index, Name, Number);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error != "")
            {
                value = false;
            }
            return value;
        }

        public bool PBookPhoneDelete(string Index)
        {
            _Error = "";
            bool value = false;
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.DeletePBookMEM(this, Index);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error != "")
            {
                value = false;
            }
            return value;
        }

        public bool ModemIsPhone()
        {
            _Error = "";
            bool ret = false;
            bool hasopen = true;
            try
            {
                if (!this.IsOpen)
                {
                    hasopen = false;
                    this.Open();
                    Thread.Sleep(500);
                }
                _Online = KeepAlive();
                if (_Online)
                {
                    this.ReadIMEI();
                    this.ReadIMSI();
                    if (_IMSI != "" && _IMEI != "")
                    {
                        ret = true;
                    }
                }
            }
            catch (Exception) { }
            finally
            {
                if (this.IsOpen && !hasopen)
                {
                    this.Close();
                }
            }
            return ret;
        }

        public SMSService SMSGetService()
        {
            _Error = "";
            SMSService value = new SMSService();
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.SMSGetMessageService(this);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error != "")
            {
                value = new SMSService();
            }
            _SMSService = value;
            return _SMSService;
        }

        public SMSService SMSSetService(int valueService)
        {
            _Error = "";
            SMSService value = new SMSService();
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.SMSsetMessageService(this,valueService);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error != "")
            {
                value = new SMSService();
            }
            _SMSService = value;
            return _SMSService;
        }

        public bool SMSSetBroadcastMessage(int valueMode)
        {
            _Error = "";
            bool value = false;
            if (this.IsOpen)
            {
                _Online = KeepAlive();
                if (_Online)
                {
                    value = GSMAPI.SMSSetBroadcastMessage(this, valueMode);
                }
            }
            else
            {
                _Error = "ERROR PORT NOT OPEN";
            }
            if (this.Error != "")
            {
                value = false;
            }
            return value;
        }

        #endregion

        #region Private Methods

        private List<SMSStorage> InternalMessagesLocation(LocationSMS Loc)
        {
            List<SMSStorage> ret = new List<SMSStorage>();
            foreach (SMSStorage item in _SMSMessages)
            {
                if (item.Location == Loc)
                {
                    ret.Add(item);
                }
            }
            return ret;
        }

        private void InitInternalVar()
        {
            _Error = "";
            _Model = "";
            _BatteryLevel = null;
            _SignalLevel = null;
            _SignalOper = "";
            _CurrentChatSet = "";
            _Indicators = new GSMIndicator();
            _ActiveStatus = ActiveStatusEnum.Disconnected;
            _Alarms = new List<GSMAlarm>();
            _validCharset = new List<string>();
            _Online = false;
            _InternalCommand = false;
            _IMSI = "";
            _IMEI = "";
            _portEncode = new ASCIIEncoding();
            _ExistLineIndentification = false;
            _EnabledLineIndentification = false;
            _ExistSMSTextFormat = false;
            _ExistSMSPDUFormat = false;
            _ValidATCommands = new ModelATCommands();
            _StoragesSMS = new StoragesSMS();
            _SMSMessages = new List<SMSStorage>();
            _SMSService = new SMSService();
            _SMSStatusReport = new List<StatusSMSReport>();

        }

        #endregion
    }
}
